#!/usr/bin/python3
# ******************************************************************************
# Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
# licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Author: DisNight
# Create: 2020-12-28
# ******************************************************************************/
"""
About the method of OSC
"""
import os
import subprocess
import argparse
import shutil

"""
need to add osc config (touch ~/.oscrc)
[general]
apiurl=osc-repo
no_verify=1
build-root=/root/osc/buildroot

[osc-repo]
user=account
pass=pwd
"""


def osc_download(save_dir, proj, pkg, repo="standard_aarch64", arch="aarch64"):
    """
    download bin rpms from obs
    user need to set osc config before use this api
    Args:
        save_dir: save dir
        proj: proj
        pkg: pkg
        repo: repo
        arch: arch

    Returns:

    """
    if not save_dir:
        save_dir = pkg + "_bin"
    cmd = "osc getbinaries {proj} {pkg} {repo} {arch} --debug -d {sd}".format(
        proj=proj,
        pkg=pkg,
        repo=repo,
        arch=arch,
        sd=save_dir
    )
    try:
        proc_new = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return None, None
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()
    return stdout_new.decode('utf-8', 'ignore'), returncode


def osc_ls_binaries_list(proj, pkg, repo="standard_aarch64", arch="aarch64"):
    """
    get binaries list from obs
    user need to set osc config before use this api
    Args:
        proj: proj
        pkg: pkg
        repo: repo
        arch: arch

    Returns:

    """
    if not proj or not pkg:
        return []
    cmd = "osc ls -b {proj} {pkg} {repo} {arch}".format(
        proj=proj,
        pkg=pkg,
        repo=repo,
        arch=arch
    )
    try:
        proc_new = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return "", 0
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()
    return stdout_new.decode('utf-8', 'ignore'), returncode


def osc_api_set_project_flag(proj, flag="build", status="enable"):
    """
    The osc api sets project flag
    Args:
        proj: proj
        flag: flag
        status: status

    Returns:

    """
    cmd = "osc api -X POST \"/source/{proj}?cmd=set_flag&flag={flag}&status={status}\"".format(
        proj=proj,
        flag=flag,
        status=status
    )
    try:
        proc_new = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return None, None
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()
    return stdout_new.decode('utf-8', 'ignore'), returncode


def osc_api_set_package_flag(proj, pkg, flag="build", status="enable"):
    cmd = "osc api -X POST \"/source/{proj}/{pkg}?cmd=set_flag&flag={flag}&status={status}\"".format(
        proj=proj,
        pkg=pkg,
        flag=flag,
        status=status
    )
    try:
        proc_new = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
    except OSError as err:
        if err.errno == errno.ENOENT:
            logger.error("Command %s not found." % cmd)
        return None, None
    stdout_new, stderr_new = proc_new.communicate()
    returncode = proc_new.returncode
    proc_new.poll()
    return stdout_new.decode('utf-8', 'ignore'), returncode


def osc_rm_unused_file(file_dir, recur=True):
    """
    remove unused file "_statistics" and "_buildenv"
    Args:
        file_dir: file_dir
        recur: recur

    Returns:
        None: None
    """
    if not os.path.isdir(file_dir):
        return False
    with os.scandir(file_dir) as dir_iter:
        for entry in dir_iter:
            current_path = os.path.join(file_dir, entry.name)
            if entry.is_file():
                if _is_unused_file(entry.name):
                    os.remove(current_path)
            elif entry.is_dir() and recur:
                osc_rm_unused_file(current_path)


def get_all_bin_name_list(data):
    """
    parse binaries list from [osc ls -b] result
    Args:
        data: data

    Returns:
        result: result
    """
    result = []
    for line in data:
        bin_name = _get_simple_bin_name(line.strip())
        if bin_name:
            result.append(bin_name)
    return result


def get_all_bin_name(file_dir, recur=True):
    """
    get all rpm name downloaded by "osc getbinaries" cmd
    Args:
        file_dir: file_dir
        recur: recur

    Returns:
        result: result
    """
    if not os.path.isdir(file_dir):
        return []
    result = []
    with os.scandir(file_dir) as dir_iter:
        for entry in dir_iter:
            if entry.is_file():
                bin_name = _get_simple_bin_name(entry.name)
                if bin_name:
                    result.append(bin_name)
            elif entry.is_dir() and recur:
                result.extend(
                    _get_all_bin_name(
                        os.path.join(file_dir, entry.name)
                    )
                )
    return result


def _get_simple_bin_name(file_name):
    """
    get bin rpm name
    Args:
        file_name: file_name

    Returns:
        file_name: The name of the split file
    """
    if not file_name.endswith((".aarch64.rpm", ".noarch.rpm", ".x86_64.rpm", ".src.rpm")):
        return ""
    return file_name.rsplit("-", 2)[0]


def _is_unused_file(file_name):
    """
    unused file "_statistics" and "_buildenv"
    Args:
        file_name: file_name

    Returns:
        file_name: The name of the split file
    """
    return file_name.startswith("_")


def has_python3_subpkg(pkg_name, proj):
    """
    has python3 subpkg
    Args:
        pkg_name: pkg_name
        proj: proj

    Returns:
        True or False
    """
    stdout, code = osc_ls_binaries_list(proj, pkg_name)
    bin_list = get_all_bin_name_list(stdout.splitlines())
    for bin_name in bin_list:
        if "python3" in bin_name:
            return True
    return False


def get_osc_pkg_nvr(pkg_name, proj, repo="standard_aarch64", arch="aarch64"):
    """
    get osc pkg nvr
    Args:
        pkg_name: pkg_name
        proj: proj
        repo: repo
        arch: arch

    Returns:
        name: name
        ver: ver
        rel: rel
    """
    stdout, code = osc_ls_binaries_list(proj, pkg_name, repo=repo, arch=arch)
    name = pkg_name
    ver = ""
    rel = ""
    for line in stdout.splitlines():
        if line.strip().endswith(".src.rpm"):
            nvr = line.strip().rsplit(".", 2)[0]
            nvr_list = nvr.rsplit("-", 2)
            name = nvr_list[0] if len(nvr_list) > 0 else pkg_name
            ver = nvr_list[1] if len(nvr_list) > 1 else ""
            rel = nvr_list[2].split(".oe1")[0] if len(nvr_list) > 2 else ""
    return name, ver, rel


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--file", default="", required=True,
                        help="file of pkg list")
    parser.add_argument("-p", "--project", default="", required=True,
                        help="project in obs")
    parser.add_argument("--flag", default="build",
                        help="type of flag")
    parser.add_argument("--status", default="enable",
                        help="project in obs")
    args = parser.parse_args()

    if not os.path.exists(args.file):
        logging.error("{} not exists".format(args.file))
        exit()
    logging.info("set-proj-flag: proj:[{}] flag:[{}] status:[{}]".format(
        args.proj,
        args.flag,
        "disable"
    ))
    osc_api_set_project_flag(args.proj, args.flag, "disable")
    with open(args.file, "r") as f:
        for line in f:
            if line.strip():
                logging.info("set-flag: proj:[{}] pkg:[{}] flag:[{}] status:[{}]".format(
                    args.project,
                    line.strip(),
                    args.flag,
                    args.status
                ))
                osc_api_set_package_flag(args.project, line.strip(), args.flag, args.status)
